//============================================================================
// Copyright (C) 2013 Brett R. Jones
//
// Issued to public domain 2013
//
// brettjones1900@gmail.com
// http://www.p2panarchy.com
//============================================================================
#include "VxSktDefs.h"
#include "VxUtilLib.h"
#include "VxGlobals.h"
#include "VxCommon.h"
#include <time.h>
#include <string>
#ifndef WIN_PLATFORM
    #include <sys/time.h>
#endif // WIN_PLATFORM

//============================================================================
// globals
//============================================================================
U32						g_u32SysTimeSec		= 0;		// unix time stamp.. seconds since jan 1, 1970
U32						g_u32GmtTimeSec		= 0;		// unix time stamp.. seconds since jan 1, 1970 gmt time
U32						g_u32ElapsedTimeMs	= 0;		// elapsed time ( app alive time ) milliseconds
S64						g_s64SysTimeMs		= 0;		// system time in milliseconds
S64						g_u64StartupTimeMs	= 0;		// unix time in milliseconds of first update ( application start )
S32						g_s32GmtTimeOffs	= 0;		// offset in seconds to turn local time to gmt time

namespace
{
	std::string			g_strAppRootDir			= "/sdcard/TruthOrDare/";
	std::string			g_strAppDataDir			= "/sdcard/TruthOrDare/data/";
	std::string			g_strApplicationName	= "Truth Or Dare";
	std::string			g_strNetworkName		= "TodNet";

	bool				g_bIsAppShuttingDown	= false;
	bool				g_bIsNetLoopbackAllowed = false;
	bool				g_bIsUdpEnabled			= true;
	bool				g_bIsDebugEnabled		= true;
	bool				g_bIsPaidApp			= false;
}

//============================================================================
//=== startup/shutdown ===//
//============================================================================
void VxSetAppIsShuttingDown( bool bIsShuttingDown )
{
	g_bIsAppShuttingDown = bIsShuttingDown;
}

//============================================================================
bool VxIsAppShuttingDown( void )
{
	return g_bIsAppShuttingDown;
}

//============================================================================
U16 VxGetAppVersion( void )
{
	return APP_VERSION;
}

//============================================================================
const char * VxGetAppVersionString( void )
{
	static std::string strAppVersion;
	static bool isSet = false;
	if( false == isSet )
	{
		U16 u16AppVersion = VxGetAppVersion();
		char as8Buf[32];
		sprintf( as8Buf, "%d.%d.%d",
			(u16AppVersion & 0xff00) >> 8,
			(u16AppVersion & 0x00f0) >> 4,
			(u16AppVersion & 0x000f)
			);
		strAppVersion = as8Buf;
	}
	return strAppVersion.c_str();
}

//============================================================================
void VxSetIsPaidApp( bool isPaidApp )
{
	g_bIsPaidApp = isPaidApp;
}

//============================================================================
bool VxIsPaidApp( void )
{
	return g_bIsPaidApp;
}

//============================================================================
//! set application name
void VxSetApplicationName( const char * pAppName )
{
	g_strApplicationName = pAppName;
}

//============================================================================
const char * VxGetApplicationName( void )
{
	return g_strApplicationName.c_str();
}

//============================================================================
void VxSetUdpEnable( bool enableUpnp )
{
	g_bIsUdpEnabled = enableUpnp;
}

//============================================================================
bool VxIsUdpEnabled( void )
{
	return g_bIsUdpEnabled;
}

//============================================================================
void VxSetDebugEnable( bool enableDebug )
{
	g_bIsDebugEnabled = enableDebug;
}

//============================================================================
bool VxIsDebugEnabled( void )
{
	return g_bIsDebugEnabled;
}

//============================================================================
//=== time ===//
//============================================================================
//============================================================================
#ifdef WIN_PLATFORM
// create gettimeofday function that acts like the unix version
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
#define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
#else
#define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL
#endif

struct timezone
{
	int  tz_minuteswest; /* minutes W of Greenwich */
	int  tz_dsttime;     /* type of dst correction */
};
void UnixTimeToFileTime(time_t t, LPFILETIME pft)
{
	// Note that LONGLONG is a 64-bit value
	LONGLONG ll;

	ll = Int32x32To64(t, 10000000) + 116444736000000000;
	pft->dwLowDateTime = (DWORD)ll;
	pft->dwHighDateTime = ll >> 32;
}

int gettimeofday(struct timeval *tv, struct timezone *tz)
{
	FILETIME ft;
	unsigned __int64 tmpres = 0;
	static int tzflag;

	if (NULL != tv)
	{
		GetSystemTimeAsFileTime(&ft);

		tmpres |= ft.dwHighDateTime;
		tmpres <<= 32;
		tmpres |= ft.dwLowDateTime;

		/*converting file time to unix epoch*/
		tmpres -= DELTA_EPOCH_IN_MICROSECS;
		tmpres /= 10;  /*convert into microseconds*/
		tv->tv_sec = (long)(tmpres / 1000000UL);
		tv->tv_usec = (long)(tmpres % 1000000UL);
	}

	if (NULL != tz)
	{
		if (!tzflag)
		{
			_tzset();
			tzflag++;
		}
		//tz->tz_minuteswest = _timezone / 60;
		//tz->tz_dsttime = _daylight;
	}
	return 0;
}
#endif //WIN_PLATFORM

//============================================================================
void CalculateGmtOffset( void )
{
	//time_t posix_time = timegm(NULL); // Linux specific line
	//g_s32GmtTimeOffs = ((int)g_u32SysTimeSec - (int)posix_time);
}

//============================================================================
//! Update system time
void VxUpdateSystemTime( void )
{
#ifdef WIN_PLATFORM
	// FILETIME is 100 nanoseconds since JAN 1, 1601
	FILETIME ft;
	GetSystemTimeAsFileTime(&ft);
	// takes the last modified date
	LARGE_INTEGER date, adjust;
	date.HighPart = ft.dwHighDateTime;
	date.LowPart = ft.dwLowDateTime;
	// 100-nanoseconds = milliseconds * 10000
	adjust.QuadPart = 11644473600000 * 10000;
	// removes the difference between 1970 and 1601
	date.QuadPart -= adjust.QuadPart;
	// convert from 100-nanoseconds to milliseconds
	g_s64SysTimeMs = date.QuadPart / 10000;
#else
	struct timeval  now;
	gettimeofday(&now, NULL);
	g_s64SysTimeMs = ((U64)now.tv_sec*1000 + (U64)(now.tv_usec / 1000));
#endif // WIN_PLATFORM

	// convert millisec to seconds
	g_u32SysTimeSec = (U32)(g_s64SysTimeMs/1000);
	if( 0 == g_u64StartupTimeMs )
	{
		g_u64StartupTimeMs = g_s64SysTimeMs;
	}
	g_u32ElapsedTimeMs = (U32)(g_s64SysTimeMs - g_u64StartupTimeMs);

	static int iCheckGmtOffset = 1000;
	if( 0 == iCheckGmtOffset )
	{
		iCheckGmtOffset = 1000;
		CalculateGmtOffset();
	}
	iCheckGmtOffset--;
	g_u32GmtTimeSec = LocalToUtcTime( g_u32SysTimeSec ); 
}


//============================================================================
//=== miscellaneous ===//
//============================================================================
//============================================================================
//! return default tcp port for rogue connections
U16 VxGetRogueConnectionsDefaultTcpPort()
{
#ifdef ANDROID_PLATFORM
	return 45455;
#else
	return 45454;
#endif // ANDROID_PLATFORM
}
//============================================================================
//! return default udp port for rogue connections
U16 VxGetRogueConnectionsDefaultUdpPort()
{
	return 45454;
}

//============================================================================
const char * VxGetRogueNetworkName()
{
	return g_strNetworkName.c_str();
}

//============================================================================
void VxSetRogueNetworkName( const char * pNetName )
{
	g_strNetworkName = pNetName;
}

//============================================================================
//! set true if loop back is allowed ( default is false )
void VxSetNetworkLoopbackAllowed( bool bIsLoopbackAllowed )
{
	g_bIsNetLoopbackAllowed = bIsLoopbackAllowed;
}

//============================================================================
//! return true if loop back is allowed
bool VxIsNetworkLoopbackAllowed( void )
{
	return g_bIsNetLoopbackAllowed;
}

//============================================================================
//=== directories ===//
//============================================================================
//! get root directory this app stores data in
std::string&	VxGetAppRootDir( void ) 
{ 
	return g_strAppRootDir; 
}

//! set root directory this app has data in
void			VxSetAppRootDir( std::string& strDir )
{ 
	g_strAppRootDir = strDir; 
}

//! get root directory this app writes data to
std::string&	VxGetAppDataDir( void )
{ 
	return g_strAppDataDir; 
}

//! set root directory this app writes data to
void			VxSetAppDataDir( std::string& strDir )
{
	g_strAppDataDir = strDir;
}

